#pragma once

#include "iostream"
#include "vector"
#include "algorithm"

using namespace std;
/*HJJ QQ479287006
 *题⽬链接：https://leetcode-cn.com/problems/ones-and-zeroes/
给你⼀个⼆进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最⼤⼦集的⼤⼩，该⼦集中 最多 有 m 个 0 和 n 个 1 。
如果 x 的所有元素也是 y 的元素，集合 x 是集合 y 的 ⼦集 。
示例 1：
输⼊：strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出：4
解释：最多有 5 个 0 和 3 个 1 的最⼤⼦集是 {"10","0001","1","0"} ，因此答案是 4 。
其他满⾜题意但较⼩的⼦集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满⾜题意，因为它含 4
个 1 ，⼤于 n 的值 3 。
示例 2：
输⼊：strs = ["10", "0", "1"], m = 1, n = 1
输出：2
解释：最⼤的⼦集是 {"0", "1"} ，所以答案是 2 。
提示：
1 <= strs.length <= 600
1 <= strs[i].length <= 100
strs[i] 仅由 '0' 和 '1' 组成
1 <= m, n <= 100
 * */



/**
1. 确定dp数组（dp table）以及下标的含义
dp[i][j]：最多有i个0和j个1的strs的最⼤⼦集的⼤⼩为dp[i][j]。
2. 确定递推公式
dp[i][j] 可以由前⼀个strs⾥的字符串推导出来，strs⾥的字符串有zeroNum个0，oneNum个1。
dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
然后我们在遍历的过程中，取dp[i][j]的最⼤值。
所以递推公式：dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
此时⼤家可以回想⼀下01背包的递推公式：dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
对⽐⼀下就会发现，字符串的zeroNum和oneNum相当于物品的重量（weight[i]），字符串本身的个数
相当于物品的价值（value[i]）。
这就是⼀个典型的01背包！ 只不过物品的重量有了两个维度⽽已。
3. dp数组如何初始化
在动态规划：关于01背包问题，你该了解这些！（滚动数组）中已经讲解了，01背包的dp数组初始化为
0就可以。
因为物品价值不会是负数，初始为0，保证递推的时候dp[i][j]不会被初始值覆盖。
4. 确定遍历顺序
在动态规划：关于01背包问题，你该了解这些！（滚动数组）中，我们讲到了01背包为什么⼀定是外层
for循环遍历物品，内层for循环遍历背包容量且从后向前遍历！
那么本题也是，物品就是strs⾥的字符串，背包容量就是题⽬描述中的m和n。
 * */
//TODO 不会
int findMaxForm(vector<string> &strs, int m, int n) {

    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); // 默认初始化0

    for (const auto &item : strs) {
        int oneNum = 0, zeroNum = 0;
        //统计数量
        for (char c : str) {
            if (c == '0') zeroNum++;
            else oneNum++;
        }

        //这俩交换也可以
        for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历！
            for (int j = n; j >= oneNum; j--) {
                //为什么要+1 我擦
                dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
            }
        }


    }


}